package utils

import (
	"encoding/xml"
	"net/http"
)

// S3Error represents a structured error response that is compatible with the S3 API.
type S3Error struct {
	XMLName   xml.Name `xml:"Error"`
	Code      string   `xml:"Code"`
	Message   string   `xml:"Message"`
	Resource  string   `xml:"Resource,omitempty"`
	RequestID string   `xml:"RequestId,omitempty"`
	HostID    string   `xml:"HostId,omitempty"`

	// HTTPStatusCode is the HTTP status code that should be sent with this error.
	// This field is not part of the XML response.
	HTTPStatusCode int `xml:"-"`
}

// Error implements the error interface.
func (e *S3Error) Error() string {
	return e.Message
}

// NewS3Error creates a new S3Error.
func NewS3Error(statusCode int, code, message string) *S3Error {
	return &S3Error{
		HTTPStatusCode: statusCode,
		Code:           code,
		Message:        message,
	}
}

// Pre-defined S3 errors for common cases.
var (
	ErrBucketAlreadyExists             = NewS3Error(http.StatusConflict, "BucketAlreadyOwnedByYou", "The requested bucket name is not available. The bucket namespace is shared by all users of the system. Please select a different name and try again.")
	ErrNoSuchKey                       = NewS3Error(http.StatusNotFound, "NoSuchKey", "The specified key does not exist.")
	ErrNoSuchBucket                    = NewS3Error(http.StatusNotFound, "NoSuchBucket", "The specified bucket does not exist.")
	ErrBucketNotEmpty                  = NewS3Error(http.StatusConflict, "BucketNotEmpty", "The bucket you tried to delete is not empty.")
	ErrNoSuchBucketPolicy              = NewS3Error(http.StatusNotFound, "NoSuchBucketPolicy", "The specified bucket does not have a bucket policy.")
	ErrNoSuchLifecycleConfiguration    = NewS3Error(http.StatusNotFound, "NoSuchLifecycleConfiguration", "The lifecycle configuration does not exist.")
	ErrMalformedLifecycleConfiguration = NewS3Error(http.StatusBadRequest, "MalformedLifecycleConfiguration", "The lifecycle configuration is malformed.")
	// Add other common errors here.
)

// WriteErrorResponseHTTP writes S3Error using net/http primitives.
func WriteErrorResponseHTTP(w http.ResponseWriter, err *S3Error) {
	if w == nil || err == nil {
		return
	}
	w.Header().Set("Content-Type", "application/xml")
	w.WriteHeader(err.HTTPStatusCode)
	xmlBytes, _ := xml.MarshalIndent(err, "", "  ")
	_, _ = w.Write(xmlBytes)
}
